/*
 * Codé par: Tristan Gosselin
 * Commenté par: Tristan Gosselin
 * **************************
 * Classe DbConnection
 * Contient la connection à la base de données
 * Contient toutes les méthode d'accès à la base de donnée (UPDATE, ADD, DELETE...)
 */
package logicielrestaurant;
import com.almworks.sqlite4java.*; //Utilisation du plugin SQLite4Java comme driver et connection utility
import java.io.*;
import java.util.*;
import javax.swing.JOptionPane;


public class DbConnection 
{
    ///
    /// Méthode qui retourne la connection à la base de donnée
    /// Évite de hardcode la connection dans chaque méthode d'accès
    ///
    public static SQLiteConnection GetConnection()
    {
         return new SQLiteConnection(new File("../Restaurant"));
    }    
    
    ///
    /// Méthode qui retourne une liste de CategoriePaiement avec tous les categories de paiements
    ///
    public static List<CategoriePaiement> getAllTypePaiements() 
    {
        // Get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'une nouvelle liste de CategoriePaiement
        List<CategoriePaiement> listePaiements = new ArrayList<CategoriePaiement>();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Categorie_Paiement");
            try {
              // Pour chaques entrées trouvé on crée un object CategoriePaiement et on l'ajoute à la liste
              while (st.step()) { 
                  CategoriePaiement c = new CategoriePaiement();
                  c.setId(st.columnInt(0));
                  c.setNom(st.columnString(1));
                  listePaiements.add(c);
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
            JOptionPane.showMessageDialog(null, e);
        }
        //retour de la liste de CategoriePaiement
        return listePaiements;
    }
    
    ///
    /// Méthode qui retourne une liste de Produits avec tous les produits
    ///
    public static List<Produit> getAllProduits() 
    {
        // Get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'une nouvelle liste de Produit
        List<Produit> listeProduits = new ArrayList<Produit>();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Produits");
            try {
                // Pour chaques entrées trouvé on crée un object Produit et on l'ajoute à la liste
              while (st.step()) {
                  Produit p = new Produit();
                  p.setId(st.columnInt(0));
                  p.setCategorie(getCategorieProduit(st.columnInt(1)));
                  p.setNom(st.columnString(2));
                  p.setPrix(st.columnDouble(3));
                  listeProduits.add(p);
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour de la liste de Produit
        return listeProduits;
    }
    
    ///
    /// Méthode qui retourne une liste de Commande pour une table Donnée
    ///
    public static List<Commande> getAllCommandesTable(Table t) 
    {
        // Get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'une nouvelle liste de Commande
        List<Commande> liste =  new ArrayList<Commande>();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Commandes where IdTable = " + t.getId());
            try {
                // Pour chaques entrées trouvé on crée un object Commande et on l'ajoute à la liste
              while (st.step()) {
                  Commande c = new Commande();
                  c.setNoClient(st.columnInt(0));
                  c.setId(st.columnInt(1));
                  c.setTable(t);
                  c.setServeur(getServeur(st.columnInt(3)));
                  liste.add(c);
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour de la liste de Commande
        return liste;
    }
    
    ///
    /// Méthode qui retourne une liste de produits pour une commande donnée
    ///
    public static List<Produit> getAllProduitsCommande(Commande c) 
    {
        // Get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'une nouvelle liste de Produits et une liste de int qui contiendra les id de produits
        List<Produit> listeProduits =  new ArrayList<Produit>();
        List<Integer> listeIdProduit = new ArrayList<Integer>();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Commandes_Produits where IdCommande = " + c.getId());
            try {
                // Get de tous les id produits et ajout à la liste
              while (st.step()) {
                  listeIdProduit.add(st.columnInt(2));
              }
              // Pour chaque ID produit trouvé plus haut, on trouve les infos du produit associer 
              // et ajout a un objet Produit et Add à la liste
              for (int i = 0; i < listeIdProduit.size();i++)
              {
                  st = db.prepare("SELECT * FROM Produits where ID = " + listeIdProduit.get(i));
                  st.step();
                  Produit p = new Produit();
                  p.setId(st.columnInt(0));
                  p.setCategorie(getCategorieProduit(st.columnInt(1)));
                  p.setNom(st.columnString(2));
                  p.setPrix(st.columnDouble(3));
                  listeProduits.add(p);
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour de la liste de Produit
        return listeProduits;
    }
    
    ///
    /// Méthode qui retourne un Produit selon un ID de Produit donné
    ///
    public static Produit getProduit(int id) 
    {
        // get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'un nouveau produit
        Produit p = new Produit();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Produits where id = " + id);
            try {
                // Si le produit est trouvé ? on inscrit les détails dans l'object Produit
              while (st.step()) {
                  p.setId(st.columnInt(0));
                  p.setCategorie(getCategorieProduit(st.columnInt(1)));
                  p.setNom(st.columnString(2));
                  p.setPrix(st.columnDouble(3));
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour du produit
        return p;
    }
    
    ///
    /// Méthode qui retourne un CategorieProduit selon un ID de CategorieProduit donné
    ///
    public static CategorieProduit getCategorieProduit(int id) 
    {
        // get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'un nouveau CategorieProduit
        CategorieProduit categorie = new CategorieProduit();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Categorie_Produits where id = " + id);
            try {
                // Si le categorieProduit est trouvé ? on inscrit les détails dans l'object categorieProduit
              while (st.step()) 
              {
                  categorie.setId(st.columnInt(0));
                  categorie.setNom(st.columnString(1));
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour du categorieProduit
        return categorie;
    }
    
    ///
    /// Méthode qui retourne un Serveur selon un numEmployer de Serveur donné
    ///
    public static Serveur getServeur(int numEmploye) 
    {
        // get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'un nouveau Serveur
        Serveur serveur = new Serveur();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Serveurs WHERE NumeroEmploye = " + numEmploye);
            try {
                // Si le Serveur est trouvé ? on inscrit les détails dans l'object Serveur
              while (st.step()) 
              {
                  serveur.setId(st.columnInt(0));
                  serveur.setNumero(st.columnInt(1));
                  serveur.setUsername(st.columnString(2));
                  serveur.setPrenom(st.columnString(4));
                  serveur.setNom(st.columnString(5));
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour du serveur
        return serveur;
    }
    
    ///
    /// Méthode qui retourne un Table selon un numero de table donné
    ///
    public static Table getTable(int numeroTable) 
    {
        //get de la connection
        SQLiteConnection db = GetConnection();
        //Déclaration d'une nouvelle Table
        Table table = new Table();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM TablesRestaurant where NoTable = " + numeroTable);
            try {
                // Si la Table est trouvée ? on inscrit les détails dans l'object Table
              while (st.step()) 
              {
                  table.setOccupe(st.columnInt(0));
                  table.setPret(st.columnInt(1));
                  table.setId(st.columnInt(2));
                  table.setNumero(st.columnInt(3));
                  table.setDescription(st.columnString(4));
              }
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour de la table
        return table;
    }
    
    ///
    /// Méthode qui retourne une Commande selon un numero de client et une table donné
    ///
    public static Commande getCommande(Table t, int noClient) 
    {
        //get de la connection
        SQLiteConnection db = GetConnection();
        // déclaration d'une nouvelle Commande
        Commande c = new Commande();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Commandes where IdTable = " + t.getId() + " AND NoClient = " + noClient);
            try 
            {
                // Si la Table est trouvée ? on inscrit les détails dans l'object Table
                st.step() ;        
                  c.setNoClient(st.columnInt(0));
                  c.setId(st.columnInt(1));
                  c.setTable(t);
                  c.setServeur(getServeur(st.columnInt(3)));
            }
            finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour de la commande
        return c;
    }
    
    ///
    /// Méthode qui retourne VRAI ou FAUX si la table a des commandes associés
    ///
    public static boolean VerifierDispoTable(Table t) 
    {
        //get de la connection
        SQLiteConnection db = GetConnection();
        // déclaration d'une variable booleennne qui sera retournée
        boolean occupe = false;
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("SELECT * FROM Commandes where IdTable = "+ t.getId());
            try {
                //Si elle est occupée ? true : false
              occupe = st.step();
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        //retour du boolean
        return occupe;
    }
    
    ///
    /// Méthode qui met a jour les status Pret et occupé pour une table donnée
    ///
    public static void UpdateTable(Table t) 
    {
        //get de la connection
        SQLiteConnection db = GetConnection();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("UPDATE TablesRestaurant SET Pret=" + t.getPret() + ", occupe=" + t.getOccupe() + " WHERE NoTable=" + t.getNumero());
            try {
                //Éxécution du update
              st.step();
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
    }
    
    ///
    /// Méthode qui insert une commande dans la base de donnée
    ///
    public static int SaveCommande(Commande c) 
    {
        //get de la connection
        SQLiteConnection db = GetConnection();
        // déclaration d'une variable qui contiendra le ID de la commande crée
        int idCommande = 0;
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("INSERT INTO Commandes (NoClient, IdTable, IdServeur, DateCommande) VALUES (" + c.getNoClient() + " , " + c.getTable().getId() + " , " +  c.getServeur().getId() + " , '" + c.getdateCommande() + "')");
            try {
              // Éxécution de l'ajout de la commande
              st.step();
              // Select du Id de la commande qui vient d'être créé et on la store dans la variable
              st = db.prepare("SELECT ID FROM Commandes where NoClient = " + c.getNoClient() + " AND IdTable = "+ c.getTable().getId());
              st.step();
              idCommande = st.columnInt(0);
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        // retour du id de la commande créee
        return idCommande;
    }
    
    ///
    /// Méthode qui enregistre une facture et supprime les commandes associées
    ///
    public static int PayerTable(Facture f, List<Commande> l) 
    {
        //get de la connection
        SQLiteConnection db = GetConnection();
        // déclaration d'une variable qui contiendra le ID de la facture crée
        int idFacture = 0;
        try
        {
            // Ouverture de la base de donnée
            SQLiteStatement st = null;
            db.open(true);
            try {
                //Pour chaque commande, on delete la comamnde dans la table et les produits associés
                for (int i =0; i<l.size(); i++)
                {
                    st = db.prepare("DELETE FROM Commandes WHERE ID = " + l.get(i).getId());
                    st.step();
                    st = db.prepare("DELETE FROM Commandes_Produits WHERE IdCommande = " + l.get(i).getId());
                    st.step();
                }
              // Insertion de la facture dans la base de donnée
              st = db.prepare("INSERT INTO Factures (IdServeur, DateFacture, TypePaiement, Prix, PrixTotal) VALUES (" + f.getServeur().getId() + " , '" + f.getDateFacture().toString() + "' , " +  f.getTypePaiement().getId() + " , " + f.getPrix() + " , " + f.getPrixTotal() + ")");  
              st.step();
              // Select de la facture crée dans la base de donnée et get de son ID
              st = db.prepare("SELECT ID FROM Factures where DateFacture = '" + f.getDateFacture().toString() + "' AND IdServeur = " + f.getServeur().getId());
              st.step();
              idFacture = st.columnInt(0);
            } finally {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
        JOptionPane.showMessageDialog(null, e);
        }
        // retour du id de la facture crée
        return idFacture;
    }
    
    ///
    /// Méthode qui insert une produitCommande dans la base de donnée
    ///
    public static void SaveItemsCommande(ProduitsCommande c)
    {
        //get de la connection
        SQLiteConnection db = GetConnection();
        try
        {
            // Ouverture de la base de donnée et formation de la requête
            db.open(true);
            SQLiteStatement st = db.prepare("INSERT INTO Commandes_Produits (IdCommande, IdItem, Quantite, Commentaires) VALUES (" + c.getCommande().getId() + " , " + c.getProduit().getId() + " , " +  c.getQuantite() + " , '" + c.getCommentaire() + "')");
            try 
            {
                //effecture l'insertion
              st.step();
            }
            finally 
            {
                //fermeture du statement
              st.dispose();
            }
            //fermeture de la connection
            db.dispose();
        }
        catch(SQLiteException e){
            // on affiche l'exception s'il y a lieu
            JOptionPane.showMessageDialog(null, e);
        }
    }   
}
